查看原文
其他

50 岁阿姨的程序员梦

脚本之家 2022-05-10

The following article is from 吴师兄学算法 Author 吴师兄

 关注
“脚本之家
”,与百万开发者在一起

出处:吴师兄学算法(ID:CXYxiaowu)

如若转载请联系原公众号

最近在小红书上看到这样一个帖子:一个 50 岁阿姨开始在 LeetCode 上刷题,当她第一次提交通过时,感受是好玩与兴奋。

起初我以为她是营销号,但点开主页之后发现她确实只是在分享她第一次刷题成功的喜悦。

在这里,还是挺佩服她的。

扫了一眼代码,不难注意到,代码的解题思路是暴力的解法。

今天就顺着这个话题和大家聊一下:新手如何有效的刷算法题。

如果你想要开始刷题,那么第一步就是:打开 LeetCode 官网,点击标签,选择一道顺眼的题目开始刷。

就像这个 50 岁的阿姨一样选题。

注意,在这过程中,不要左思右盼,不要去搜索与思考到底是刷 LeetCode 好还是去牛客网刷剑指 Offer 好。

我作为一名算法小白的时候,就犯了这个错误:在粗略的学习基本的数据结构与算法后,准备开始刷题,总想着找一个最有效最好的刷题平台。

一会在 LeetCode 题解区逛逛,一会在牛客网看看面经,结果就是整个人烦躁不安,焦虑迷茫,题没有刷几道,羡慕嫉妒恨却增加了几分:别人的代码怎么这么简洁 ?别人的 Offer 怎么这么亮眼?

经过痛定思定之后,我开始自我剖析自己想好好刷题却无效的原因:

1、没有接受自己是算法小白的事实

我那时候只是按图索骥般的稍微系统的学习了基础数据结构与算法知识,根本没有真正的利用这些知识去处理问题。

在刷题的过程中,总想证明自己可以的,别人可以写成简洁高效的解题方法,我也要!于是去不停的找题证明自己,结果就是越刷越没有效果,自己根本就看不懂题目考察的数据结构与思想。

整个人完全奔溃,不刷题了,不准备算法面试了,不准备跳槽了!

后来我不停的告诫自己:作为一名非科班的程序员,肯定比不上他们呀,如果随随便便的学了一点就能刷题顺利,那别人大学四年不白学了!

所以前期先接受自己的思考方式,暴力解法其实也是一种有效的解法。

2、没有合理的刷题

我只是盲目的追求刷题的数量,即使刷了 200 道,脑中依旧一团浆糊。

后来才明白,吃透一道题目比乱刷十道题目更有价值。

经过不断的摸索与试验,形成了自己的一套刷题路径。

  • 自己的解法
  • 网上好的解法
  • 自己的解法可以改进的地方
  • 不停的优化
  • 寻找相同的题型重复练习
  • 总结

每一个题目都经过至少一遍这样的迭代,彻底吃透一道题进而掌握一种题型。

以一道极其简单的动态规划题为例 ,LeetCode 第 70 号问题:爬楼梯。当时的我根本不知道动态规划的相关概念,什么状态,什么转移方程,通通没听过。

没错,当时就那么菜!

二话不说,直接使用暴力解法。

class Solution {
    public int climbStairs(int n) {
        return calcWays(n);
    }
    private int calcWays( int n ){
        if ( n == 1return 1;
        if ( n == 2return 2;
        return calcWays(n-1) + calcWays(n-2);
    }
}

很明显,无脑的递归暴力解法包含了大量的重复计算,提交上去直接标红提示超出时间限制。

后来看了网上高票答案的分析,知道了备忘录的概念,于是很容易写出优化后的代码。

//采用备忘录的方式来存子问题的解以避免大量的重复计算

class Solution 
    int[] memo; 
    public int climbStairs(int n) 
        memo = new int[n+1]; 
        return calcWays(n); 
    } 
    private int calcWays( int n )
        if ( n == 1return 1
        if ( n == 2return 2
        if (memo[n] == 0
           memo[n] =  calcWays(n-1) + calcWays(n-2); 
        return memo[n]; 
    } 

}

再后来,发现备忘录是自顶向下的方式,稍许变动,修改为自低向上的递推方式就是动态规划的形式。

class Solution 

    public int climbStairs(int n) 
        int[] memo = new int[n+1]; 
        memo[0] = 1
        memo[1] = 1

        for(int i = 2 ; i <= n; i++){ 
            memo[i] = memo[i-1] + memo[i-2]; 
        } 
        return memo[n]; 
    } 
}

按照这样的刷题路径下来,发现对这类题型有了初步的思考途径,有了发力点,再也不会一筹莫展:看题懵逼半小时,Coding 只会按空格。

彻底搞懂这题后,就需要找到类似的题型,然后不断的重复练习:最小路径和、整数拆分、完全平方数、解码方法、不同路径、不同路径 II。

通过这些练习,寻找题目中的共同点,为什么这类题型都可以这样思考呢?

慢慢的,知道了最优子结构、状态转移方程、重叠子问题的概念,不知不觉动态规划的知识点已经掌握了 80%。

再遇到更高难度的动态规划的题目时,心里也明白,一时半会没做成无法就是最优子结构、状态转移方程、重叠子问题没有理清楚。

这样长期坚持下来,接触新的题型时也可以从容不迫的思考。

喜欢大家也能找到像这位阿姨那样刷题的乐趣。


程序员专属卫衣

商品直购链接 👇

  推荐阅读:

终于!我找到程序员爱穿卫衣的原因了!!!

攻克让你畏惧的算法,十行代码搞定快速排序

算法岗是什么?我适不适合算法岗?选什么方向的算法岗?

一致性 Hash 算法原理总结

推荐:4 款专属极客卫衣,程序员秒懂!

每日打卡赢积分兑换书籍入口

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存